• Pipeline overview
  • Dataset generation
    • Outcome variable: Binarizing and recoding details
  • Data exploration and visualization
  • Robust feature evaluation
    • Feature importances: Random Forest
      • Mean decrease in impurity (MDI)
      • Permutation importance
      • MDI vs Permutation importance
    • Feature importances: LASSO
      • Coefficient-based variable importance
      • Permutation importance
      • Coefficient vs. Permutation importance
  • Generation of final model
    • Performance
    • Features: permutation importance
    • Comparison with bootstrap results
    • Features: permutation importance
    • Comparison with bootstrap results
  • Other cleanup

Project run parameters

no_tasks=2
seed = 9384
outcome = 'p_drug'
fbase = '/scratch/p_gaydosh_lab/DSI/'
results_directory <- str_c(fbase, outcome, '/results_full_h2o_2_tsunk')
set.seed(seed)

Purpose. In this work, we will explore the relation between identified measures of despair of interest (e.g., personality measures of self-consciousness, individual and composite item scores from the CES-D assessment) and descriptors of diseases of despair. We will achieve this goal through modeling the outcomes based on the included predictors, and robustly assess the importance of the included features in predicting the outcomes via bootstrapping. We will use two well-known machine learning models, random forests and LASSO, which are both frequently used to measure the relative importance of the predictors included in the models. Lastly, we’ll generate trained and tuned models using this reduced feature set which can be used by others wish to predict the identified outcomes.

Subject inclusion. For this investigation, we will omit the entirety of Wave 2. This is commonly done in analyses of AddHealth data due the design of the original study. Otherwise, our dataset will include only subjects who have predictor and outcome data in all of the waves.

Outcome variables. In this experiment, we assess suicidal ideation at Wave 5.

Predictor variables. The predictors for these models are hand-picked, and based on previous work, relevance, and subject matter expertise. The set of predictors and the set of outcomes are disjoint. Predictors from Waves 1-4 (excluding Wave 2, see above) are included, and will be detailed in the following analysis.

Pipeline overview

Dataset generation

The predictors we will be using will be the the variable predictor_list loaded from 10-import-data.Rmd file. These initial set of predictors will be based of the list of variables that describe anxiety, depression, and optimism.

## set outcome variable of interest
filebase = '/scratch/p_gaydosh_lab'

#create data in specified form
dataset_list <- generate_datasets(outcome, binarize=FALSE, filebase=filebase, seed_val=seed)
Parsed with column specification:
cols(
  variable = col_character(),
  wave = col_double(),
  na_level = col_double(),
  type = col_character()
)
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".0 subjects removed from dataset.
[1] "Recoding Missing Factor Variables"
[1] "Number of factor variables being recoded :  98"
[1] "Factor variables being recoded : "
 [1] "h1fs1"   "h1fs3"   "h1fs4"   "h1fs5"   "h1fs6"   "h1fs7"   "h1fs11"  "h1fs15"  "h1fs16"  "h1fs17" 
[11] "h1fs19"  "h1ee14"  "h1ee12"  "h1ds14"  "h1ed9"   "h1ed7"   "h1ds3"   "h1fv7"   "h1fv1"   "h1fv8"  
[21] "h1jo9"   "h1ds13"  "h1ds12"  "h1ds11"  "h3sp5"   "h3sp6"   "h3sp7"   "h3sp8"   "h3sp9"   "h3sp10" 
[31] "h3sp11"  "h3sp12"  "h3sp13"  "h3ec56"  "h3ds18h" "h3ds18a" "h3ds18i" "h3to49"  "h3ds6"   "h3ds5"  
[41] "h3ds4"   "h4id5h"  "h4mh18"  "h4mh19"  "h4mh20"  "h4mh21"  "h4mh22"  "h4mh23"  "h4mh24"  "h4mh25" 
[51] "h4mh26"  "h4mh27"  "h4id5j"  "h4pe6"   "h4pe14"  "h4pe22"  "h4pe30"  "h4pe7"   "h4pe15"  "h4pe23" 
[61] "h4pe31"  "h4mh3"   "h4mh4"   "h4mh5"   "h4mh6"   "h4mh2"   "hdl"     "ldl"     "tg"      "h4bpcls"
[71] "h4ds7"   "h4ds19"  "h4ds14"  "h4ds20"  "h4ds6"   "h4ds5"   "h4ds4"   "h4cj17"  "h5id6g"  "h5ss0a" 
[81] "h5ss0b"  "h5ss0c"  "h5ss0d"  "h5ss0e"  "h5id6i"  "h5pe1"   "h5pe2"   "h5pe3"   "h5mn1"   "h5mn2"  
[91] "h5mn3"   "h5mn4"   "h5cj1d"  "h5cj1e"  "h5cj1f"  "h5cj1b"  "h5cj1c"  "h5cj1a" 
[1] "h1fs1"
[1] "h1fs3"
[1] "h1fs4"
[1] "h1fs5"
[1] "h1fs6"
[1] "h1fs7"
[1] "h1fs11"
[1] "h1fs15"
[1] "h1fs16"
[1] "h1fs17"
[1] "h1fs19"
[1] "h1ee14"
[1] "h1ee12"
[1] "h1ds14"
[1] "h1ed9"
[1] "h1ed7"
[1] "h1ds3"
[1] "h1fv7"
[1] "h1fv1"
[1] "h1fv8"
[1] "h1jo9"
[1] "h1ds13"
[1] "h1ds12"
[1] "h1ds11"
[1] "h3sp5"
[1] "h3sp6"
[1] "h3sp7"
[1] "h3sp8"
[1] "h3sp9"
[1] "h3sp10"
[1] "h3sp11"
[1] "h3sp12"
[1] "h3sp13"
[1] "h3ec56"
[1] "h3ds18h"
[1] "h3ds18a"
[1] "h3ds18i"
[1] "h3to49"
[1] "h3ds6"
[1] "h3ds5"
[1] "h3ds4"
[1] "h4id5h"
[1] "h4mh18"
[1] "h4mh19"
[1] "h4mh20"
[1] "h4mh21"
[1] "h4mh22"
[1] "h4mh23"
[1] "h4mh24"
[1] "h4mh25"
[1] "h4mh26"
[1] "h4mh27"
[1] "h4id5j"
[1] "h4pe6"
[1] "h4pe14"
[1] "h4pe22"
[1] "h4pe30"
[1] "h4pe7"
[1] "h4pe15"
[1] "h4pe23"
[1] "h4pe31"
[1] "h4mh3"
[1] "h4mh4"
[1] "h4mh5"
[1] "h4mh6"
[1] "h4mh2"
[1] "hdl"
[1] "ldl"
[1] "tg"
[1] "h4bpcls"
[1] "h4ds7"
[1] "h4ds19"
[1] "h4ds14"
[1] "h4ds20"
[1] "h4ds6"
[1] "h4ds5"
[1] "h4ds4"
[1] "h4cj17"
[1] "h5id6g"
[1] "h5ss0a"
[1] "h5ss0b"
[1] "h5ss0c"
[1] "h5ss0d"
[1] "h5ss0e"
[1] "h5id6i"
[1] "h5pe1"
[1] "h5pe2"
[1] "h5pe3"
[1] "h5mn1"
[1] "h5mn2"
[1] "h5mn3"
[1] "h5mn4"
[1] "h5cj1d"
[1] "h5cj1e"
[1] "h5cj1f"
[1] "h5cj1b"
[1] "h5cj1c"
[1] "h5cj1a"
   h1fs1    h1fs3    h1fs4    h1fs5    h1fs6    h1fs7   h1fs11   h1fs15   h1fs16   h1fs17   h1fs19   h1ee14 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h1ee12   h1ds14    h1ed9    h1ed7    h1ds3    h1fv7    h1fv1    h1fv8    h1jo9   h1ds13   h1ds12   h1ds11 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
   h3sp5    h3sp6    h3sp7    h3sp8    h3sp9   h3sp10   h3sp11   h3sp12   h3sp13   h3ec56  h3ds18h  h3ds18a 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
 h3ds18i   h3to49    h3ds6    h3ds5    h3ds4   h4id5h   h4mh18   h4mh19   h4mh20   h4mh21   h4mh22   h4mh23 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h4mh24   h4mh25   h4mh26   h4mh27   h4id5j    h4pe6   h4pe14   h4pe22   h4pe30    h4pe7   h4pe15   h4pe23 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h4pe31    h4mh3    h4mh4    h4mh5    h4mh6    h4mh2      hdl      ldl       tg  h4bpcls    h4ds7   h4ds19 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h4ds14   h4ds20    h4ds6    h4ds5    h4ds4   h4cj17   h5id6g   h5ss0a   h5ss0b   h5ss0c   h5ss0d   h5ss0e 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h5id6i    h5pe1    h5pe2    h5pe3    h5mn1    h5mn2    h5mn3    h5mn4   h5cj1d   h5cj1e   h5cj1f   h5cj1b 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h5cj1c   h5cj1a 
"factor" "factor" 
[1] "Recoding Missing Numeric Variables"
[1] "Number of numeric variables being recoded :  7"
[1] "Numeric variables being recoded : "
[1] "h1ed2"   "h4bmi"   "hba1c"   "crp"     "h4waist" "h4sbp"   "h4dbp"  
#parse out dataset components
wave_data <- dataset_list$wave_data
full_dataset <- dataset_list$full_dataset
ds_raw <- dataset_list$ds_raw_outcome
ds <- dataset_list$ds_final

#ml splits of the data
training_df <- dataset_list$training_df
validation_df <- dataset_list$validation_df
testing_df <- dataset_list$testing_df

Outcome variable: Binarizing and recoding details

The following table details the values present in the outcome variable. As we can see, we need to convert the variable into a factor, and drop the NAs.

ds_raw %>% 
  group_by(.data[[outcome]]) %>% 
  summarise(total = n(), type = class(.data[[outcome]]))

ds %>% 
  group_by(.data[[outcome]]) %>% 
  summarise(total = n(), type = class(.data[[outcome]]))

print(str_c('Total number of subjects in unprocessed outcome data: ', nrow(ds_raw)))
[1] "Total number of subjects in unprocessed outcome data: 9349"
print(str_c('Total number of subjects in processed outcome data: ', nrow(ds)))
[1] "Total number of subjects in processed outcome data: 9263"
print(str_c('Total subjects dropped due to NA or skip: ', nrow(ds_raw)-nrow(ds)))
[1] "Total subjects dropped due to NA or skip: 86"

The table also demonstrates that the classes are very imbalanced, with about 14x the negative class as compared with the positive class. This is displayed graphically for easy consumption below.

ds_raw %>%
  explore_outcome(ds, outcome)
The original raw outcome data is displayed by converting it to a factor.  For more information about its actual type, investigate the ds_raw dataframe.  It is most likely a double.

After dropping the NAs, we see that we now have 9168 rows, which is consistent with the table above. The distribution of the data has a distinct imbalance as noted above. I think this warrants using pr_auc as the optimization and selection metric.

Data exploration and visualization

Here, we comment about the general characteristics of the data based on the provided visualizations. We comment on missingness of data, any strange or unusual behavior (e.g., strong imbalances), and any correlation that sticks out.

#Report about the characteristics of the subjects left out of the join
ds %>% explore_dropped()

# Visualize distributions of variables of interest
ds %>% 
  dplyr::select(-aid) %>%
  graph_bar_discrete(df = .,
                     plot_title = "Distributions of Discrete Variables",
                     max_categories = 50,
                     num_rows = 3,
                     num_cols = 3,
                     x_axis_size = 12,
                     y_axis_size = 12,
                     title_size = 15)

ds %>%
  graph_missing(only_missing = TRUE,
                title = "Percent Missing",
                box_line_size = .5,
                label_size = .5,
                x_axis_size = 12,
                y_axis_size = 12,
                title_size = 15)

ds %>%
  #dplyr::select(1:20) %>%
  pairwise_cramers_v() %>%
  plot_cramer_v(x_axis_angle = 90,
                plot_title = "Association among Categorical Variables",
                interactive = TRUE)
h4id5hh5id6gh1fs1h1fs3h1fs4h1fs5h1fs6h1fs7h1fs11h1fs15h1fs16h1fs17h1fs19h3sp5h3sp6h3sp7h3sp8h3sp9h3sp10h3sp11h3sp12h3sp13h4mh18h4mh19h4mh20h4mh21h4mh22h4mh23h4mh24h4mh25h4mh26h4mh27h5ss0ah5ss0bh5ss0ch5ss0dh5ss0eh5id6ih4id5jh4pe6h4pe14h4pe22h4pe30h4pe7h4pe15h4pe23h4pe31h5pe1h5pe2h5pe3h4mh3h4mh4h4mh5h4mh6h4mh2h5mn1h5mn2h5mn3h5mn4h1ee14h1ee12h3ec56hdlldltgh4bpclsh1ds14h1ed9h1ed7h1ds3h1fv7h1fv1h1fv8h1jo9h1ds13h1ds12h1ds11h3ds18hh3ds18ah3ds18ih3to49h3ds6h3ds5h3ds4h4ds7h4ds19h4ds14h4ds20h4ds6h4ds5h4ds4h4cj17h5cj1dh5cj1eh5cj1fh5cj1bh5cj1ch5cj1ap_drugh4id5hh5id6gh1fs1h1fs3h1fs4h1fs5h1fs6h1fs7h1fs11h1fs15h1fs16h1fs17h1fs19h3sp5h3sp6h3sp7h3sp8h3sp9h3sp10h3sp11h3sp12h3sp13h4mh18h4mh19h4mh20h4mh21h4mh22h4mh23h4mh24h4mh25h4mh26h4mh27h5ss0ah5ss0bh5ss0ch5ss0dh5ss0eh5id6ih4id5jh4pe6h4pe14h4pe22h4pe30h4pe7h4pe15h4pe23h4pe31h5pe1h5pe2h5pe3h4mh3h4mh4h4mh5h4mh6h4mh2h5mn1h5mn2h5mn3h5mn4h1ee14h1ee12h3ec56hdlldltgh4bpclsh1ds14h1ed9h1ed7h1ds3h1fv7h1fv1h1fv8h1jo9h1ds13h1ds12h1ds11h3ds18hh3ds18ah3ds18ih3to49h3ds6h3ds5h3ds4h4ds7h4ds19h4ds14h4ds20h4ds6h4ds5h4ds4h4cj17h5cj1dh5cj1eh5cj1fh5cj1bh5cj1c
Association among Categorical Variables

The correlation plot suggests that there are several variables we might think about removing. Firstly, there are moderate correlations among the individual predictor blocks; this is due to the way that they are ordered, since they’re essentially grouped into subsets. Addtionally, some predictor pairs have extremely high correlations, like (h4id5j, h4mh26) (correlation of 0.72), and many variables in the h4mh* series. (h3id5j, h4id5h) also has high correlation > 0.5. We may want to consider removing several of these in addition to the age variables because it may cause feature importance masking within our approaches.

Robust feature evaluation

The following table displays the mean performance metrics for the bootstrapped models on the validation set, removing values for which there are NA.


mean_bs_rf_perf <- bs_rf_perf %>%
  summarise_if(is.numeric, mean, na.rm=TRUE) %>%
  mutate(model = 'bs_rf') %>%
  dplyr::select(model, everything())

mean_bs_rf_perf

As shown, the bootstrapped models tend to have high specificity but low sensitivity, indicating that there is a challenge in identifying subjects with suicidal ideation.

Feature importances: Random Forest

Mean decrease in impurity (MDI)

boot_rf_mdi <- list(bs_rf_mdi) %>%
  get_median_placement(use_base_var = TRUE) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, att_name, overall_rank)

head(boot_rf_mdi, 20)

This table returns the MDI variable importance ranks that returned from each of the bootstrapped models.

# Needs to be fixed so that axes don't overlap each other and obscure understanding
plot_placement_boxplot(list(bs_rf_mdi))

Permutation importance

Now, let’s look at the permutation importance:

met <- 'pr_auc'
bs_rf_perm <- bs_rf_perm_plt %>%
  get_permute_placement(metric_oi=met) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(bs_rf_perm, 20)

MDI vs Permutation importance

In this step, we assess the differences generated between the different types of importances.

cbind(boot_rf_mdi[1:20,], dplyr::select(bs_rf_perm[1:20,], -all_of(met)))

As shown, the MDI importance suffers from imbalances due to the number of values associated with a predictor. Because the wave ages have so many more values than the other factors, this artificially inflates their importance in MDI. The permutation importance is more intuitive.

plot_permute_var_imp(bs_rf_perm, metric = met)

In this step, we model the relation between the outcomes and the predictors using a linear regression with L2 regularization. This drives the importance of unimportant and redudant features towards zero.

mean_bs_lasso_perf <- bs_lasso_perf %>%
  summarise_if(is.numeric, mean, na.rm=TRUE) %>% 
  mutate(model='bs_lasso') %>%
  dplyr::select(model, everything())

mean_bs_lasso_perf

Feature importances: LASSO

Coefficient-based variable importance

boot_lasso_mdi <- list(bs_lasso_mdi) %>%
  get_median_placement(use_base_var = TRUE) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, att_name, overall_rank)

head(boot_lasso_mdi, 20)
plot_placement_boxplot(list(bs_lasso_mdi))

Permutation importance

bs_lasso_perm <- bs_lasso_perm_plt %>%
  get_permute_placement(metric_oi=met) %>% #set in random forest section
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(bs_lasso_perm, 20)
plot_permute_var_imp(bs_lasso_perm, metric = met)

Coefficient vs. Permutation importance

Now, we compare the feature importances generated by the two different approaches. The traditional method of evaluating feature importance for regression methods is through analysis of the coefficients.

cbind(boot_lasso_mdi[1:20,], dplyr::select(bs_lasso_perm[1:20,], -met))

The following table compares the mean performance of bootstrapped random forests to the mean performance of bootstrapped LASSO methods.

bs_comp_perfs <- bind_rows(mean_bs_rf_perf, mean_bs_lasso_perf) 
bs_comp_perfs

Here, we look at the aggregated results of the bootstrapped predictors and compare the models generated to each other.

joined_results <- bs_rf_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(bs_lasso_perm, -met), by=c("predictor", "att_name"), suffix=c('.rf', '.lasso')) %>%
  mutate(mean_rank = (overall_rank.rf+overall_rank.lasso)/2) %>%
  arrange(mean_rank)

head(joined_results, 20)

The following visualization provides the intuition about the differences in the rankings between model types. They’re ordered by the overall mean importance, and for a given variable, the differences in rank are shown.

# Comparison of top_n features
joined_results %>%
  compare_feature_select(interactive = TRUE,
                         top_n = 100,
                         opacity = 0.50,
                         plot_title = "Permutation Importance of Predictors by Model")
0306090S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S26Q15 DO NOT EXPECT THINGS MY WAY-W4S21Q20 12 MO,SHOT/STABBED SOMEONE-W4ldlS06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S9Q1 ALWAYS OPTIM ABOUT FUT-W5S9Q2 NOT EXPECT THINGS MY WAY-W5S26Q18I 12 MO,SHOT/STABBED SOMEONE-W3S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S26Q23 EXPECT MORE GOOD THAN BAD-W4S14Q26 PAST 7 DAYS FELT SAD-W4S10Q0E PAST 7 DAY NOT WORTH-W5S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3tgS26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S31Q8 SHOT/STABBED SOMEONE-W1S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S26Q6 WORRY ABOUT THINGS-W4S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S26Q22 I GET STRESSED OUT EASILY-W4S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4hdlS14Q5 LST MNTH THINGS GOING YOUR WAY-W4S14Q24 PAST 7 DAYS FELT HAPPY-W4S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S9Q3 EXPECT MORE GOOD-W5S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S26Q5 12 MO,OFT SELL DRUGS-W3S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S21Q5 12 MO,OFT SELL DRUGS-W4S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S26Q14 NOT EASILY BOTHERED BY THINGS-W4S31Q1 SAW SHOOTING/STABBING OF PERSON-W1S10Q0D PAST 7 DAY SAD-W5S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S27 MEASURED WAIST (CM) -W4S27 SYSTOLIC BLOOD PRESSURE-W4S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S14Q27 PAST 7 DAYS FELT DISLIKED-W4S29Q11 USE OR THREATEN WITH A WEAPON-W1S10Q0C PAST 7 DAY HAPPY-W5S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S5Q9 EXPELLED FROM SCHOOL-W1S13Q4 LAST MO DIFFS OVERWHELM-W5S10Q0B PAST 7 DAY DEPRESSED-W5S12Q12 PAST 7 DAYS WERE SAD-W3S10Q0A PAST 7 DAY SHAKE BLUE-W5S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S10Q19 LIFE NOT WORTH LIVING-W1S10Q6 FELT DEPRESSED-W1S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5S14Q1C 12 MO SELL DRUGS-W5S29Q12 SELL DRUGS-W1S10Q3 HAD THE BLUES-W1S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S14Q2 HOW OFTEN FEEL ISOLATED-W4S27 BLOOD PRESSURE CLASS -W4S29Q13 STEAL WORTH < $50-W1S5Q6G EVER BEEN DX WITH DEPRESSION-W5S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5BIOLOGICAL SEX-W1S14Q22 PAST 7 DAYS FELT DEPRESSED-W4S26Q30 DO NOT WORRY ABOUT PAST-W4S10Q16 FELT SAD-W1S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S5Q2 FREQ-SKIPPED SCHOOL-W1S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3h3bmiS12Q9 PAST 7 DAYS WERE DEPRESSED-W3S27 BMI -W4S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4crpS12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S38Q12 CHANCES-LIVE TO AGE 35-W1S06Q5H EVER BEEN DX WITH DEPRESSION-W4S10Q1 BOTHERED BY THINGS-W1S10Q17 FELT PEOPLE DISLIKE YOU-W1S27 DIASTOLIC BLOOD PRESSURE -W4S38Q14 CHANCES-KILLED BY AGE 21-W1S10Q11 HAPPY-W1S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S10Q15 ENJOYED LIFE-W1S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S22Q17 EVER INCARCERATED-W4S30Q9 DRIVE WHILE DRUNK-W1S10Q7 TOO TIRED TO DO THINGS-W1S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1S29Q14 TAKE PART IN A GROUP FIGHT-W1S10Q5 TROUBLE KEEPING MIND FOCUSED-W1S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1age_w5
overall_rank.lassooverall_rank.rfPermutation Importance of Predictors by ModelPlacementsPredictorsmodel

Generation of final model

In this step, we build the final model for the random forest. We use slightly more values in order to come up with the best model, keeping in mind the number of combinations that are required to run to evaluate the grid.


final_rf_perf = NULL
  
# read file array
final_rf_perfs = load_from_csv(final_rf_perf, results_directory, no_tasks)

# get the index of the best performance and best performance
final_rfmodel_ind <- which.max(dplyr::select(final_rf_perfs, met) %>% pull(met))
final_rf_perf <- final_rf_perfs %>% slice(final_rfmodel_ind)

# load the model of interest
final_model_rf <- load_best_model('final_rf_model', results_directory, final_rfmodel_ind)

Performance

The final random forest performance metrics are shown below:

# show model final performance
print(final_rf_perf)

Features: permutation importance


final_rf_perm_plt = NULL
  
# read best perm plt
final_rf_perm_plt = load_from_csv(final_rf_perm_plt, results_directory, best_ind=final_rfmodel_ind)
final_rf_perm <- final_rf_perm_plt %>%
  get_permute_placement(metric_oi=met) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(final_rf_perm, 20)
plot_permute_var_imp(final_rf_perm, metric = met)

Comparison with bootstrap results

This section investigates the differences in the bootstrap results vs the features generated from the random forest final model. The following table shows the overall differences in rank.

rf_joined_results <- final_rf_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(bs_rf_perm, -met), by=c("predictor", "att_name"), suffix=c('.final', '.bootstrap')) %>%
  mutate(mean_rank = (overall_rank.final + overall_rank.bootstrap)/2) %>%
  arrange(mean_rank)

head(rf_joined_results, 20)

The following plot provides visualizations for the difference in the final model rankings vs the bootstrap.

# Comparison of top_n features
rf_joined_results %>%
  compare_feature_select(sel_cols = c("overall_rank.final", "overall_rank.bootstrap"),
    interactive = TRUE,
    top_n = 100,
    opacity = 0.50,
    plot_title = "Permutation Importance of Predictors: Final vs. Bootstrap")
0255075100S29Q12 SELL DRUGS-W1S21Q6 12 MO,OFT STEAL SOMETHING/<$50-W4S26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S5Q9 EXPELLED FROM SCHOOL-W1S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S31Q1 SAW SHOOTING/STABBING OF PERSON-W1S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S10Q19 LIFE NOT WORTH LIVING-W1BIOLOGICAL SEX-W1S26Q5 12 MO,OFT SELL DRUGS-W3S14Q1B 12 MO STEAL SOMETHING/>$50-W5S29Q13 STEAL WORTH < $50-W1S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S21Q20 12 MO,SHOT/STABBED SOMEONE-W4S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S5Q2 FREQ-SKIPPED SCHOOL-W1crpS10Q3 HAD THE BLUES-W1S21Q5 12 MO,OFT SELL DRUGS-W4one_race5S26Q15 DO NOT EXPECT THINGS MY WAY-W4hba1cS14Q26 PAST 7 DAYS FELT SAD-W4S10Q6 FELT DEPRESSED-W1S10Q16 FELT SAD-W1S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S26Q23 EXPECT MORE GOOD THAN BAD-W4S10Q0E PAST 7 DAY NOT WORTH-W5S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S10Q1 BOTHERED BY THINGS-W1S12Q12 PAST 7 DAYS WERE SAD-W3S10Q17 FELT PEOPLE DISLIKE YOU-W1S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S14Q24 PAST 7 DAYS FELT HAPPY-W4h3bmiS14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S38Q12 CHANCES-LIVE TO AGE 35-W1S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S14Q27 PAST 7 DAYS FELT DISLIKED-W4S29Q14 TAKE PART IN A GROUP FIGHT-W1S38Q14 CHANCES-KILLED BY AGE 21-W1S10Q11 HAPPY-W1S26Q6 WORRY ABOUT THINGS-W4S12Q9 PAST 7 DAYS WERE DEPRESSED-W3S9Q2 NOT EXPECT THINGS MY WAY-W5S27 BLOOD PRESSURE CLASS -W4S9Q1 ALWAYS OPTIM ABOUT FUT-W5S10Q15 ENJOYED LIFE-W1S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S26Q22 I GET STRESSED OUT EASILY-W4S14Q1C 12 MO SELL DRUGS-W5S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4ldlS14Q5 LST MNTH THINGS GOING YOUR WAY-W4S14Q2 HOW OFTEN FEEL ISOLATED-W4S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S27 BMI -W4S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S26Q14 NOT EASILY BOTHERED BY THINGS-W4S06Q5H EVER BEEN DX WITH DEPRESSION-W4S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1S9Q3 EXPECT MORE GOOD-W5S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S14Q22 PAST 7 DAYS FELT DEPRESSED-W4S14Q3 LST MNTH UNABLE CONTROL THINGS-W4hdlS27 SYSTOLIC BLOOD PRESSURE-W4tgS12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S10Q0D PAST 7 DAY SAD-W5S10Q0B PAST 7 DAY DEPRESSED-W5S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3S30Q9 DRIVE WHILE DRUNK-W1S26Q30 DO NOT WORRY ABOUT PAST-W4S27 DIASTOLIC BLOOD PRESSURE -W4S10Q5 TROUBLE KEEPING MIND FOCUSED-W1S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S27 MEASURED WAIST (CM) -W4S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4age_w5S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1S10Q7 TOO TIRED TO DO THINGS-W1S13Q4 LAST MO DIFFS OVERWHELM-W5S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3S10Q0C PAST 7 DAY HAPPY-W5S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5S10Q0A PAST 7 DAY SHAKE BLUE-W5S22Q17 EVER INCARCERATED-W4S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S5Q6G EVER BEEN DX WITH DEPRESSION-W5
overall_rank.bootstrapoverall_rank.finalPermutation Importance of Predictors: Final vs. BootstrapPlacementsPredictorsmodel

Now, we create the final model for LASSO. There is no substantial difference between this method and the bootstrap methods, other than the data upon which the model is being built.


final_lasso_perf = NULL
  
# read file array
final_lasso_perfs = load_from_csv(final_lasso_perf, results_directory, no_tasks)

# get the index of the best performance and best performance
final_lassomodel_ind <- which.max(dplyr::select(final_lasso_perfs, met) %>% pull(met))
final_lasso_perf <- final_lasso_perfs %>% slice(final_lassomodel_ind)

# load the model of interest
final_model_lasso <- load_best_model('final_lasso_model', results_directory, final_lassomodel_ind)

The final LASSO performance metrics are shown below:

# show model final performance
print(final_lasso_perf)

Features: permutation importance


final_lasso_perm_plt = NULL

#load best index permutation from file  
final_lasso_perm_plt = load_from_csv(final_lasso_perm_plt, results_directory, best_ind=final_lassomodel_ind)
final_lasso_perm <- final_lasso_perm_plt %>%
  get_permute_placement(metric_oi=met) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(final_lasso_perm, 20)
plot_permute_var_imp(final_lasso_perm, metric = met)

Comparison with bootstrap results

This section investigates the differences in the bootstrap results vs the features generated from the LASSO final model. The following table shows the overall differences in rank.

lasso_joined_results <- final_lasso_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(bs_lasso_perm, -met), by=c("predictor", "att_name"), suffix=c('.final', '.bootstrap')) %>%
  mutate(mean_rank = (overall_rank.final + overall_rank.bootstrap)/2) %>%
  arrange(mean_rank)

head(lasso_joined_results, 20)

The following plot provides visualizations for the difference in the final model rankings vs the bootstrap.

# Comparison of top_n features
lasso_joined_results %>%
  compare_feature_select(sel_cols = c("overall_rank.final", "overall_rank.bootstrap"),
    interactive = TRUE,
    top_n = 100,
    opacity = 0.50,
    plot_title = "Permutation Importance of Predictors: Final vs. Bootstrap")
0306090S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S14Q1F 12 MO SHOT/STABBED SOMEONE-W5S14Q1E 12 MO PULL KNIFE/GUN SOMEONE-W5S14Q27 PAST 7 DAYS FELT DISLIKED-W4S14Q1D 12 MO GET IN PHYS FIGHT-W5S14Q1B 12 MO STEAL SOMETHING/>$50-W5S14Q5 LST MNTH THINGS GOING YOUR WAY-W4S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S26Q6 WORRY ABOUT THINGS-W4S26Q23 EXPECT MORE GOOD THAN BAD-W4S26Q15 DO NOT EXPECT THINGS MY WAY-W4S27 DIASTOLIC BLOOD PRESSURE -W4S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3S14Q26 PAST 7 DAYS FELT SAD-W4S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S22Q17 EVER INCARCERATED-W4S12Q9 PAST 7 DAYS WERE DEPRESSED-W3S14Q24 PAST 7 DAYS FELT HAPPY-W4S14Q22 PAST 7 DAYS FELT DEPRESSED-W4S10Q0E PAST 7 DAY NOT WORTH-W5S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S14Q2 HOW OFTEN FEEL ISOLATED-W4S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4hdlS21Q7 12 MO,OFT PART PHYS FIGHT/GRP-W4hba1cS13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S21Q6 12 MO,OFT STEAL SOMETHING/<$50-W4S21Q4 12 MO,OFT WEAPON GET SOMETHING-W4S21Q20 12 MO,SHOT/STABBED SOMEONE-W4S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S10Q0B PAST 7 DAY DEPRESSED-W5S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S10Q17 FELT PEOPLE DISLIKE YOU-W1S27 BMI -W4S9Q3 EXPECT MORE GOOD-W5S13Q4 LAST MO DIFFS OVERWHELM-W5S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S5Q6G EVER BEEN DX WITH DEPRESSION-W5S26Q14 NOT EASILY BOTHERED BY THINGS-W4S38Q12 CHANCES-LIVE TO AGE 35-W1S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S12Q12 PAST 7 DAYS WERE SAD-W3S27 MEASURED WAIST (CM) -W4S10Q0A PAST 7 DAY SHAKE BLUE-W5S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S06Q5H EVER BEEN DX WITH DEPRESSION-W4crpS15Q56 CHANCE OF-LIVING TILL AGE 35-W3S26Q5 12 MO,OFT SELL DRUGS-W3S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5S26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S26Q18I 12 MO,SHOT/STABBED SOMEONE-W3S14Q1C 12 MO SELL DRUGS-W5S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S26Q22 I GET STRESSED OUT EASILY-W4S26Q30 DO NOT WORRY ABOUT PAST-W4S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S30Q9 DRIVE WHILE DRUNK-W1S27 BLOOD PRESSURE CLASS -W4S31Q8 SHOT/STABBED SOMEONE-W1S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S21Q5 12 MO,OFT SELL DRUGS-W4S31Q1 SAW SHOOTING/STABBING OF PERSON-W1S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S10Q6 FELT DEPRESSED-W1S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S10Q3 HAD THE BLUES-W1S10Q19 LIFE NOT WORTH LIVING-W1S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S10Q16 FELT SAD-W1S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S10Q15 ENJOYED LIFE-W1S10Q11 HAPPY-W1S10Q1 BOTHERED BY THINGS-W1S5Q9 EXPELLED FROM SCHOOL-W1S38Q14 CHANCES-KILLED BY AGE 21-W1h3bmiS12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3S29Q12 SELL DRUGS-W1S29Q11 USE OR THREATEN WITH A WEAPON-W1S29Q14 TAKE PART IN A GROUP FIGHT-W1BIOLOGICAL SEX-W1S10Q5 TROUBLE KEEPING MIND FOCUSED-W1S29Q13 STEAL WORTH < $50-W1S10Q7 TOO TIRED TO DO THINGS-W1S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1age_w5S5Q2 FREQ-SKIPPED SCHOOL-W1S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1
overall_rank.bootstrapoverall_rank.finalPermutation Importance of Predictors: Final vs. BootstrapPlacementsPredictorsmodel

Here, we compare the features generated by the permutation importance between the two final models.

rf_lasso_final_joined_results <- final_rf_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(final_lasso_perm, -met), by=c("predictor", "att_name"), suffix=c('.rf', '.lasso')) %>%
  mutate(mean_rank = (overall_rank.rf+overall_rank.lasso)/2) %>%
  arrange(mean_rank)

head(rf_lasso_final_joined_results, 20)

The following visualization provides the intuition about the differences in the rankings between the final model types. They’re ordered by the overall mean importance, and for a given variable, the differences in rank are shown.

# Comparison of top_n features
rf_lasso_final_joined_results %>%
  compare_feature_select(sel_cols = c("overall_rank.rf", "overall_rank.lasso"),
    interactive = TRUE,
    top_n = 100,
    opacity = 0.50,
    plot_title = "Permutation Importance of Predictors: Random Forest vs Lasso")
0306090one_race5S21Q6 12 MO,OFT STEAL SOMETHING/<$50-W4S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S10Q17 FELT PEOPLE DISLIKE YOU-W1S31Q8 SHOT/STABBED SOMEONE-W1S12Q9 PAST 7 DAYS WERE DEPRESSED-W3S14Q26 PAST 7 DAYS FELT SAD-W4S26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S26Q23 EXPECT MORE GOOD THAN BAD-W4S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S26Q15 DO NOT EXPECT THINGS MY WAY-W4S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S10Q0D PAST 7 DAY SAD-W5S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S9Q2 NOT EXPECT THINGS MY WAY-W5S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S26Q5 12 MO,OFT SELL DRUGS-W3S29Q11 USE OR THREATEN WITH A WEAPON-W1S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S29Q12 SELL DRUGS-W1S9Q1 ALWAYS OPTIM ABOUT FUT-W5S21Q20 12 MO,SHOT/STABBED SOMEONE-W4S10Q19 LIFE NOT WORTH LIVING-W1S5Q9 EXPELLED FROM SCHOOL-W1S31Q1 SAW SHOOTING/STABBING OF PERSON-W1ldlS14Q24 PAST 7 DAYS FELT HAPPY-W4S38Q12 CHANCES-LIVE TO AGE 35-W1S10Q0E PAST 7 DAY NOT WORTH-W5S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S26Q6 WORRY ABOUT THINGS-W4S27 SYSTOLIC BLOOD PRESSURE-W4S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S10Q3 HAD THE BLUES-W1S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3BIOLOGICAL SEX-W1S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S12Q12 PAST 7 DAYS WERE SAD-W3S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S27 DIASTOLIC BLOOD PRESSURE -W4tgS10Q16 FELT SAD-W1S10Q6 FELT DEPRESSED-W1S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S14Q5 LST MNTH THINGS GOING YOUR WAY-W4S14Q2 HOW OFTEN FEEL ISOLATED-W4S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S10Q0C PAST 7 DAY HAPPY-W5S29Q14 TAKE PART IN A GROUP FIGHT-W1S21Q5 12 MO,OFT SELL DRUGS-W4S29Q13 STEAL WORTH < $50-W1S10Q1 BOTHERED BY THINGS-W1S14Q22 PAST 7 DAYS FELT DEPRESSED-W4S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5S27 BMI -W4S10Q15 ENJOYED LIFE-W1S22Q17 EVER INCARCERATED-W4hba1cS10Q11 HAPPY-W1S5Q2 FREQ-SKIPPED SCHOOL-W1S27 BLOOD PRESSURE CLASS -W4S06Q5H EVER BEEN DX WITH DEPRESSION-W4S38Q14 CHANCES-KILLED BY AGE 21-W1S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S30Q9 DRIVE WHILE DRUNK-W1S14Q1C 12 MO SELL DRUGS-W5h3bmiS10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S10Q0B PAST 7 DAY DEPRESSED-W5hdlS29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1S26Q14 NOT EASILY BOTHERED BY THINGS-W4S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S26Q22 I GET STRESSED OUT EASILY-W4S9Q3 EXPECT MORE GOOD-W5S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4S10Q5 TROUBLE KEEPING MIND FOCUSED-W1age_w5S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S26Q30 DO NOT WORRY ABOUT PAST-W4S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S27 MEASURED WAIST (CM) -W4S13Q4 LAST MO DIFFS OVERWHELM-W5S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1S12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S5Q6G EVER BEEN DX WITH DEPRESSION-W5S10Q7 TOO TIRED TO DO THINGS-W1S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5S10Q0A PAST 7 DAY SHAKE BLUE-W5S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4
overall_rank.lassooverall_rank.rfPermutation Importance of Predictors: Random Forest vs LassoPlacementsPredictorsmodel

With the final models generated, we’re now able to compare their performance metrics.

# Comparison of performance metrics
valid_perf <- get_metric_set_from_perfs(perf_list = list(final_rf_perf, final_lasso_perf)) %>%
  mutate(model = c('rf', 'lasso'))

testing_perf <- get_metric_set_from_models(testing_df, list(final_model_rf, final_model_lasso), out=outcome) %>%
  mutate(model = c('rf', 'lasso'))

Validation and selection. The following table shows the comparison between models in terms of the validation set. We can select our final model based on the best performing model according to the metric.

print(valid_perf)

Testing performance. The following shows the performance of both the models on the test set. Note that although we don’t use this test set to evaluate the final models, we can still see how our selected method would have performed.

print(testing_perf)

The following plots show a comparison between the performance of the models on the validation and test sets. Again, we don’t choose the model based on the test set, but curiosity dictates that we view this performance.

# Show plots side by side
metrics_of_interest = c('model', 'accuracy', 'bal_accuracy', 'mpce', 'sens', 'spec', 'ppv', 'npv', 'pr_auc', 'roc_auc')
valid_plt <- plot_metric_set(dplyr::select(valid_perf, all_of(metrics_of_interest)), plot_title = "Model comparison for validation set")
test_plt <- plot_metric_set(dplyr::select(testing_perf, all_of(metrics_of_interest)), plot_title = "Model comparison for testing set")
gridExtra::grid.arrange(gridExtra::arrangeGrob(valid_plt, test_plt, ncol=2, nrow=1))

Other cleanup

h2o.shutdown(FALSE)
LS0tCnRpdGxlOiAiODYtaW50ZXJwcmV0LXByLWRydWciCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0aGVtZTogbHVtZW4KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UpCmBgYAoKYGBge3Igc291cmNlIGZpbGVzLCBpbmNsdWRlPUZBTFNFfQpzb3VyY2UoImZ1bmN0aW9uX2ltcG9ydC5SIikKYGBgCgojIyBQcm9qZWN0IHJ1biBwYXJhbWV0ZXJzCmBgYHtyIHNlZWRzIGZvciByZXByb2R1Y2liaWxpdHl9Cm5vX3Rhc2tzPTIKc2VlZCA9IDkzODQKb3V0Y29tZSA9ICdwX2RydWcnCmZiYXNlID0gJy9zY3JhdGNoL3BfZ2F5ZG9zaF9sYWIvRFNJLycKcmVzdWx0c19kaXJlY3RvcnkgPC0gc3RyX2MoZmJhc2UsIG91dGNvbWUsICcvcmVzdWx0c19mdWxsX2gyb18yX3RzdW5rJykKc2V0LnNlZWQoc2VlZCkKYGBgCgoqKlB1cnBvc2UuKiogSW4gdGhpcyB3b3JrLCB3ZSB3aWxsIGV4cGxvcmUgdGhlIHJlbGF0aW9uIGJldHdlZW4gaWRlbnRpZmllZCBtZWFzdXJlcyBvZiBkZXNwYWlyIG9mIGludGVyZXN0IChlLmcuLCBwZXJzb25hbGl0eSBtZWFzdXJlcyBvZiBzZWxmLWNvbnNjaW91c25lc3MsIGluZGl2aWR1YWwgYW5kIGNvbXBvc2l0ZSBpdGVtIHNjb3JlcyBmcm9tIHRoZSBDRVMtRCBhc3Nlc3NtZW50KSBhbmQgZGVzY3JpcHRvcnMgb2YgZGlzZWFzZXMgb2YgZGVzcGFpci4gIFdlIHdpbGwgYWNoaWV2ZSB0aGlzIGdvYWwgdGhyb3VnaCBtb2RlbGluZyB0aGUgb3V0Y29tZXMgYmFzZWQgb24gdGhlIGluY2x1ZGVkIHByZWRpY3RvcnMsIGFuZCByb2J1c3RseSBhc3Nlc3MgdGhlIGltcG9ydGFuY2Ugb2YgdGhlIGluY2x1ZGVkIGZlYXR1cmVzIGluIHByZWRpY3RpbmcgdGhlIG91dGNvbWVzIHZpYSBib290c3RyYXBwaW5nLiAgV2Ugd2lsbCB1c2UgdHdvIHdlbGwta25vd24gbWFjaGluZSBsZWFybmluZyBtb2RlbHMsIHJhbmRvbSBmb3Jlc3RzIGFuZCBMQVNTTywgd2hpY2ggYXJlIGJvdGggZnJlcXVlbnRseSB1c2VkIHRvIG1lYXN1cmUgdGhlIHJlbGF0aXZlIGltcG9ydGFuY2Ugb2YgdGhlIHByZWRpY3RvcnMgaW5jbHVkZWQgaW4gdGhlIG1vZGVscy4gIExhc3RseSwgd2UnbGwgZ2VuZXJhdGUgdHJhaW5lZCBhbmQgdHVuZWQgbW9kZWxzIHVzaW5nIHRoaXMgcmVkdWNlZCBmZWF0dXJlIHNldCB3aGljaCBjYW4gYmUgdXNlZCBieSBvdGhlcnMgd2lzaCB0byBwcmVkaWN0IHRoZSBpZGVudGlmaWVkIG91dGNvbWVzLgoKKipTdWJqZWN0IGluY2x1c2lvbi4qKiBGb3IgdGhpcyBpbnZlc3RpZ2F0aW9uLCB3ZSB3aWxsIG9taXQgdGhlIGVudGlyZXR5IG9mIFdhdmUgMi4gIFRoaXMgaXMgY29tbW9ubHkgZG9uZSBpbiBhbmFseXNlcyBvZiBBZGRIZWFsdGggZGF0YSBkdWUgdGhlIGRlc2lnbiBvZiB0aGUgb3JpZ2luYWwgc3R1ZHkuICBPdGhlcndpc2UsIG91ciBkYXRhc2V0IHdpbGwgaW5jbHVkZSBvbmx5IHN1YmplY3RzIHdobyBoYXZlIHByZWRpY3RvciBhbmQgb3V0Y29tZSBkYXRhIGluIF9hbGxfIG9mIHRoZSB3YXZlcy4KCioqT3V0Y29tZSB2YXJpYWJsZXMuKiogSW4gdGhpcyBleHBlcmltZW50LCB3ZSBhc3Nlc3MgX3N1aWNpZGFsIGlkZWF0aW9uXyBhdCBXYXZlIDUuICAKCioqUHJlZGljdG9yIHZhcmlhYmxlcy4qKiBUaGUgcHJlZGljdG9ycyBmb3IgdGhlc2UgbW9kZWxzIGFyZSBoYW5kLXBpY2tlZCwgYW5kIGJhc2VkIG9uIHByZXZpb3VzIHdvcmssIHJlbGV2YW5jZSwgYW5kIHN1YmplY3QgbWF0dGVyIGV4cGVydGlzZS4gVGhlIHNldCBvZiBwcmVkaWN0b3JzIGFuZCB0aGUgc2V0IG9mIG91dGNvbWVzIGFyZSBkaXNqb2ludC4gIFByZWRpY3RvcnMgZnJvbSBXYXZlcyAxLTQgKGV4Y2x1ZGluZyBXYXZlIDIsIHNlZSBhYm92ZSkgYXJlIGluY2x1ZGVkLCBhbmQgd2lsbCBiZSBkZXRhaWxlZCBpbiB0aGUgZm9sbG93aW5nIGFuYWx5c2lzLgoKYGBge3IgbG9hZCBsaWJyYXJpZXMsIGluY2x1ZGU9RkFMU0V9CiMgVXNlIHBhY21hbiwgd2hpY2ggZm9yY2VzIGFuIGluc3RhbGwgaWYgdGhlIGxpYnJhcnkgaXNuJ3QgcHJlc2VudCBvbiB0aGUgcnVubmluZyBtYWNoaW5lCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpCiNwYWNtYW46OnBfaW5zdGFsbChwbG90bHkpCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgaDJvLCBmdXJycikKCmBgYAoKYGBge3IgaW5pdGlhbGl6YXRpb25zLCBpbmNsdWRlPUZBTFNFfQpwb3J0X25vIDwtIHN0YXJ0X2gybygpCmgyby5ub19wcm9ncmVzcygpCmZ1dHVyZTo6cGxhbihtdWx0aXByb2Nlc3MpCmBgYAoKIyBQaXBlbGluZSBvdmVydmlldwpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzUwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcuL2ltZy9waXBlbGluZV9vdmVydmlldy5qcGcnKQpgYGAKCiMgRGF0YXNldCBnZW5lcmF0aW9uCgpUaGUgcHJlZGljdG9ycyB3ZSB3aWxsIGJlIHVzaW5nIHdpbGwgYmUgdGhlIHRoZSB2YXJpYWJsZSBgcHJlZGljdG9yX2xpc3RgIGxvYWRlZCBmcm9tIGAxMC1pbXBvcnQtZGF0YS5SbWRgIGZpbGUuIFRoZXNlIGluaXRpYWwgc2V0IG9mIHByZWRpY3RvcnMgd2lsbCBiZSBiYXNlZCBvZiB0aGUgbGlzdCBvZiB2YXJpYWJsZXMgdGhhdCBkZXNjcmliZSBhbnhpZXR5LCBkZXByZXNzaW9uLCBhbmQgb3B0aW1pc20uCgpgYGB7ciBsb2FkIHJhdyBkYXRhIGFuZCBmb3JtdWxhdGUgZGF0YXNldCwgd2FybmluZz1UUlVFLCBtZXNzYWdlPVRSVUV9CiMjIHNldCBvdXRjb21lIHZhcmlhYmxlIG9mIGludGVyZXN0CmZpbGViYXNlID0gJy9zY3JhdGNoL3BfZ2F5ZG9zaF9sYWInCgojY3JlYXRlIGRhdGEgaW4gc3BlY2lmaWVkIGZvcm0KZGF0YXNldF9saXN0IDwtIGdlbmVyYXRlX2RhdGFzZXRzKG91dGNvbWUsIGJpbmFyaXplPUZBTFNFLCBmaWxlYmFzZT1maWxlYmFzZSwgc2VlZF92YWw9c2VlZCkKCiNwYXJzZSBvdXQgZGF0YXNldCBjb21wb25lbnRzCndhdmVfZGF0YSA8LSBkYXRhc2V0X2xpc3Qkd2F2ZV9kYXRhCmZ1bGxfZGF0YXNldCA8LSBkYXRhc2V0X2xpc3QkZnVsbF9kYXRhc2V0CmRzX3JhdyA8LSBkYXRhc2V0X2xpc3QkZHNfcmF3X291dGNvbWUKZHMgPC0gZGF0YXNldF9saXN0JGRzX2ZpbmFsCgojbWwgc3BsaXRzIG9mIHRoZSBkYXRhCnRyYWluaW5nX2RmIDwtIGRhdGFzZXRfbGlzdCR0cmFpbmluZ19kZgp2YWxpZGF0aW9uX2RmIDwtIGRhdGFzZXRfbGlzdCR2YWxpZGF0aW9uX2RmCnRlc3RpbmdfZGYgPC0gZGF0YXNldF9saXN0JHRlc3RpbmdfZGYKCmBgYAoKIyMgT3V0Y29tZSB2YXJpYWJsZTogQmluYXJpemluZyBhbmQgcmVjb2RpbmcgZGV0YWlscwoKVGhlIGZvbGxvd2luZyB0YWJsZSBkZXRhaWxzIHRoZSB2YWx1ZXMgcHJlc2VudCBpbiB0aGUgb3V0Y29tZSB2YXJpYWJsZS4gIEFzIHdlIGNhbiBzZWUsIHdlIG5lZWQgdG8gY29udmVydCB0aGUgdmFyaWFibGUgaW50byBhIGZhY3RvciwgYW5kIGRyb3AgdGhlIE5Bcy4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmRzX3JhdyAlPiUgCiAgZ3JvdXBfYnkoLmRhdGFbW291dGNvbWVdXSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSwgdHlwZSA9IGNsYXNzKC5kYXRhW1tvdXRjb21lXV0pKQoKZHMgJT4lIAogIGdyb3VwX2J5KC5kYXRhW1tvdXRjb21lXV0pICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBuKCksIHR5cGUgPSBjbGFzcyguZGF0YVtbb3V0Y29tZV1dKSkKCnByaW50KHN0cl9jKCdUb3RhbCBudW1iZXIgb2Ygc3ViamVjdHMgaW4gdW5wcm9jZXNzZWQgb3V0Y29tZSBkYXRhOiAnLCBucm93KGRzX3JhdykpKQpwcmludChzdHJfYygnVG90YWwgbnVtYmVyIG9mIHN1YmplY3RzIGluIHByb2Nlc3NlZCBvdXRjb21lIGRhdGE6ICcsIG5yb3coZHMpKSkKcHJpbnQoc3RyX2MoJ1RvdGFsIHN1YmplY3RzIGRyb3BwZWQgZHVlIHRvIE5BIG9yIHNraXA6ICcsIG5yb3coZHNfcmF3KS1ucm93KGRzKSkpCgpgYGAKClRoZSB0YWJsZSBhbHNvIGRlbW9uc3RyYXRlcyB0aGF0IHRoZSBjbGFzc2VzIGFyZSB2ZXJ5IGltYmFsYW5jZWQsIHdpdGggYWJvdXQgMTR4IHRoZSBuZWdhdGl2ZSBjbGFzcyBhcyBjb21wYXJlZCB3aXRoIHRoZSBwb3NpdGl2ZSBjbGFzcy4gIFRoaXMgaXMgZGlzcGxheWVkIGdyYXBoaWNhbGx5IGZvciBlYXN5IGNvbnN1bXB0aW9uIGJlbG93LgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIHdhcm5pbmc9VFJVRX0KZHNfcmF3ICU+JQogIGV4cGxvcmVfb3V0Y29tZShkcywgb3V0Y29tZSkKCmBgYAoKQWZ0ZXIgZHJvcHBpbmcgdGhlIE5Bcywgd2Ugc2VlIHRoYXQgd2Ugbm93IGhhdmUgOTE2OCByb3dzLCB3aGljaCBpcyBjb25zaXN0ZW50IHdpdGggdGhlIHRhYmxlIGFib3ZlLiAgVGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YSBoYXMgYSBkaXN0aW5jdCBpbWJhbGFuY2UgYXMgbm90ZWQgYWJvdmUuICBJIHRoaW5rIHRoaXMgd2FycmFudHMgdXNpbmcgYHByX2F1Y2AgYXMgdGhlIG9wdGltaXphdGlvbiBhbmQgc2VsZWN0aW9uIG1ldHJpYy4KCiMgRGF0YSBleHBsb3JhdGlvbiBhbmQgdmlzdWFsaXphdGlvbgpIZXJlLCB3ZSBjb21tZW50IGFib3V0IHRoZSBnZW5lcmFsIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZGF0YSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgdmlzdWFsaXphdGlvbnMuICBXZSBjb21tZW50IG9uIG1pc3NpbmduZXNzIG9mIGRhdGEsIGFueSBzdHJhbmdlIG9yIHVudXN1YWwgYmVoYXZpb3IgKGUuZy4sIHN0cm9uZyBpbWJhbGFuY2VzKSwgYW5kIGFueSBjb3JyZWxhdGlvbiB0aGF0IHN0aWNrcyBvdXQuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojUmVwb3J0IGFib3V0IHRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIHN1YmplY3RzIGxlZnQgb3V0IG9mIHRoZSBqb2luCmRzICU+JSBleHBsb3JlX2Ryb3BwZWQoKQoKYGBgCgpgYGB7ciBlZGEgZGlzdHJpYnV0aW9ucywgZmlnLndpZHRoID0gMTUsIGZpZy5oZWlnaHQ9MTV9CiMgVmlzdWFsaXplIGRpc3RyaWJ1dGlvbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0CmRzICU+JSAKICBkcGx5cjo6c2VsZWN0KC1haWQpICU+JQogIGdyYXBoX2Jhcl9kaXNjcmV0ZShkZiA9IC4sCiAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiRGlzdHJpYnV0aW9ucyBvZiBEaXNjcmV0ZSBWYXJpYWJsZXMiLAogICAgICAgICAgICAgICAgICAgICBtYXhfY2F0ZWdvcmllcyA9IDUwLAogICAgICAgICAgICAgICAgICAgICBudW1fcm93cyA9IDMsCiAgICAgICAgICAgICAgICAgICAgIG51bV9jb2xzID0gMywKICAgICAgICAgICAgICAgICAgICAgeF9heGlzX3NpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgeV9heGlzX3NpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgdGl0bGVfc2l6ZSA9IDE1KQpgYGAKCmBgYHtyIGVkYSBtaXNzaW5nfQpkcyAlPiUKICBncmFwaF9taXNzaW5nKG9ubHlfbWlzc2luZyA9IFRSVUUsCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJQZXJjZW50IE1pc3NpbmciLAogICAgICAgICAgICAgICAgYm94X2xpbmVfc2l6ZSA9IC41LAogICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IC41LAogICAgICAgICAgICAgICAgeF9heGlzX3NpemUgPSAxMiwKICAgICAgICAgICAgICAgIHlfYXhpc19zaXplID0gMTIsCiAgICAgICAgICAgICAgICB0aXRsZV9zaXplID0gMTUpCgpgYGAKCmBgYHtyIGVkYSBjb3JyZWxhdGlvbnN9CmRzICU+JQogICNkcGx5cjo6c2VsZWN0KDE6MjApICU+JQogIHBhaXJ3aXNlX2NyYW1lcnNfdigpICU+JQogIHBsb3RfY3JhbWVyX3YoeF9heGlzX2FuZ2xlID0gOTAsCiAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIkFzc29jaWF0aW9uIGFtb25nIENhdGVnb3JpY2FsIFZhcmlhYmxlcyIsCiAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZSA9IFRSVUUpCmBgYApUaGUgY29ycmVsYXRpb24gcGxvdCBzdWdnZXN0cyB0aGF0IHRoZXJlIGFyZSBzZXZlcmFsIHZhcmlhYmxlcyB3ZSBtaWdodCB0aGluayBhYm91dCByZW1vdmluZy4gIEZpcnN0bHksIHRoZXJlIGFyZSBtb2RlcmF0ZSBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGluZGl2aWR1YWwgcHJlZGljdG9yIGJsb2NrczsgdGhpcyBpcyBkdWUgdG8gdGhlIHdheSB0aGF0IHRoZXkgYXJlIG9yZGVyZWQsIHNpbmNlIHRoZXkncmUgZXNzZW50aWFsbHkgZ3JvdXBlZCBpbnRvIHN1YnNldHMuICBBZGR0aW9uYWxseSwgc29tZSBwcmVkaWN0b3IgcGFpcnMgaGF2ZSBleHRyZW1lbHkgaGlnaCBjb3JyZWxhdGlvbnMsIGxpa2UgKGg0aWQ1aiwgaDRtaDI2KSAoY29ycmVsYXRpb24gb2YgMC43MiksIGFuZCBtYW55IHZhcmlhYmxlcyBpbiB0aGUgaDRtaCogc2VyaWVzLiAgKGgzaWQ1aiwgaDRpZDVoKSBhbHNvIGhhcyBoaWdoIGNvcnJlbGF0aW9uID4gMC41LiAgV2UgbWF5IHdhbnQgdG8gY29uc2lkZXIgcmVtb3Zpbmcgc2V2ZXJhbCBvZiB0aGVzZSBpbiBhZGRpdGlvbiB0byB0aGUgYWdlIHZhcmlhYmxlcyBiZWNhdXNlIGl0IG1heSBjYXVzZSBmZWF0dXJlIGltcG9ydGFuY2UgbWFza2luZyB3aXRoaW4gb3VyIGFwcHJvYWNoZXMuCgojIFJvYnVzdCBmZWF0dXJlIGV2YWx1YXRpb24gey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpUaGUgZm9sbG93aW5nIHRhYmxlIGRpc3BsYXlzIHRoZSBtZWFuIHBlcmZvcm1hbmNlIG1ldHJpY3MgZm9yIHRoZSBib290c3RyYXBwZWQgbW9kZWxzIG9uIHRoZSB2YWxpZGF0aW9uIHNldCwgcmVtb3ZpbmcgdmFsdWVzIGZvciB3aGljaCB0aGVyZSBhcmUgTkEuCgpgYGB7ciBzYXZlL2xvYWQgcmYgYm9vdHN0cmFwIG1vZGVsIHBlcmZvcm1hbmNlLCBpbmNsdWRlPUZBTFNFfQoKYnNfcmZfcGVyZiA9IE5VTEwKCiMgZ2V0IGRhdGEgZmlsZXMKYnNfcmZfcGVyZiA9IGxvYWRfZnJvbV9jc3YoYnNfcmZfcGVyZiwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKYGBgCgoKYGBge3IgZXZhbHVhdGUgYm9vdHN0cmFwIG1vZGVsIHBlcmZvcm1hbmNlIHJmLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKbWVhbl9ic19yZl9wZXJmIDwtIGJzX3JmX3BlcmYgJT4lCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIG1lYW4sIG5hLnJtPVRSVUUpICU+JQogIG11dGF0ZShtb2RlbCA9ICdic19yZicpICU+JQogIGRwbHlyOjpzZWxlY3QobW9kZWwsIGV2ZXJ5dGhpbmcoKSkKCm1lYW5fYnNfcmZfcGVyZgpgYGAKQXMgc2hvd24sIHRoZSBib290c3RyYXBwZWQgbW9kZWxzIHRlbmQgdG8gaGF2ZSBoaWdoIHNwZWNpZmljaXR5IGJ1dCBsb3cgc2Vuc2l0aXZpdHksIGluZGljYXRpbmcgdGhhdCB0aGVyZSBpcyBhIGNoYWxsZW5nZSBpbiBpZGVudGlmeWluZyBzdWJqZWN0cyB3aXRoIHN1aWNpZGFsIGlkZWF0aW9uLgoKIyMjIEZlYXR1cmUgaW1wb3J0YW5jZXM6IFJhbmRvbSBGb3Jlc3QKIyMjIyBNZWFuIGRlY3JlYXNlIGluIGltcHVyaXR5IChNREkpCgpgYGB7ciBzYXZlL2xvYWQgcmYgYm9vdHN0cmFwIG1vZGVsIG1kaSwgaW5jbHVkZT1GQUxTRX0KCmJzX3JmX21kaSA9IE5VTEwKICAKIyBnZXQgZGF0YSBmaWxlcwpic19yZl9tZGkgPSBsb2FkX2Zyb21fY3N2KGJzX3JmX21kaSwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKCmBgYAoKYGBge3IgZXZhbHVhdGUgYm9vdHN0cmFwIG1kaX0KYm9vdF9yZl9tZGkgPC0gbGlzdChic19yZl9tZGkpICU+JQogIGdldF9tZWRpYW5fcGxhY2VtZW50KHVzZV9iYXNlX3ZhciA9IFRSVUUpICU+JQogIGFkZF9hdHRyaWJ1dGVfbmFtZXMoJ3ByZWRpY3RvcicsIGZ1bGxfZGF0YXNldCkgJT4lCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3IsIGF0dF9uYW1lLCBvdmVyYWxsX3JhbmspCgpoZWFkKGJvb3RfcmZfbWRpLCAyMCkKYGBgClRoaXMgdGFibGUgcmV0dXJucyB0aGUgTURJIHZhcmlhYmxlIGltcG9ydGFuY2UgcmFua3MgdGhhdCByZXR1cm5lZCBmcm9tIGVhY2ggb2YgdGhlIGJvb3RzdHJhcHBlZCBtb2RlbHMuCgpgYGB7ciBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEyfQojIE5lZWRzIHRvIGJlIGZpeGVkIHNvIHRoYXQgYXhlcyBkb24ndCBvdmVybGFwIGVhY2ggb3RoZXIgYW5kIG9ic2N1cmUgdW5kZXJzdGFuZGluZwpwbG90X3BsYWNlbWVudF9ib3hwbG90KGxpc3QoYnNfcmZfbWRpKSkKYGBgCgojIyMjIFBlcm11dGF0aW9uIGltcG9ydGFuY2UKTm93LCBsZXQncyBsb29rIGF0IHRoZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlOgoKYGBge3IgY29tcHV0ZS9zYXZlIG9yIGxvYWQgYnMgcmYgbW9kZWwgcGVybXV0YXRpb24sIGluY2x1ZGU9RkFMU0V9Cgpic19yZl9wZXJtX3BsdCA8LSBOVUxMCiAgCiMgZ2V0IGRhdGEgZmlsZXMKYnNfcmZfcGVybV9wbHQgPC0gbG9hZF9mcm9tX2Nzdihic19yZl9wZXJtX3BsdCwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKYGBgCgoKYGBge3IgYWdncmVnYXRlIHJmIHBlcm0gcmVzdWx0c30KbWV0IDwtICdwcl9hdWMnCmJzX3JmX3Blcm0gPC0gYnNfcmZfcGVybV9wbHQgJT4lCiAgZ2V0X3Blcm11dGVfcGxhY2VtZW50KG1ldHJpY19vaT1tZXQpICU+JQogIGFkZF9hdHRyaWJ1dGVfbmFtZXMoJ3ByZWRpY3RvcicsIGZ1bGxfZGF0YXNldCkgJT4lCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3IsIGV2ZXJ5dGhpbmcoKSkKCmhlYWQoYnNfcmZfcGVybSwgMjApCmBgYAoKIyMjIyBNREkgdnMgUGVybXV0YXRpb24gaW1wb3J0YW5jZQpJbiB0aGlzIHN0ZXAsIHdlIGFzc2VzcyB0aGUgZGlmZmVyZW5jZXMgZ2VuZXJhdGVkIGJldHdlZW4gdGhlIGRpZmZlcmVudCB0eXBlcyBvZiBpbXBvcnRhbmNlcy4KYGBge3IgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxNH0KY2JpbmQoYm9vdF9yZl9tZGlbMToyMCxdLCBkcGx5cjo6c2VsZWN0KGJzX3JmX3Blcm1bMToyMCxdLCAtYWxsX29mKG1ldCkpKQpgYGAKQXMgc2hvd24sIHRoZSBNREkgaW1wb3J0YW5jZSBzdWZmZXJzIGZyb20gaW1iYWxhbmNlcyBkdWUgdG8gdGhlIG51bWJlciBvZiB2YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIGEgcHJlZGljdG9yLiAgQmVjYXVzZSB0aGUgd2F2ZSBhZ2VzIGhhdmUgc28gbWFueSBtb3JlIHZhbHVlcyB0aGFuIHRoZSBvdGhlciBmYWN0b3JzLCB0aGlzIGFydGlmaWNpYWxseSBpbmZsYXRlcyB0aGVpciBpbXBvcnRhbmNlIGluIE1ESS4gIFRoZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIGlzIG1vcmUgaW50dWl0aXZlLgoKYGBge3IgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9wZXJtdXRlX3Zhcl9pbXAoYnNfcmZfcGVybSwgbWV0cmljID0gbWV0KQpgYGAKCgojIyBMQVNTTyBtb2RlbApJbiB0aGlzIHN0ZXAsIHdlIG1vZGVsIHRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBvdXRjb21lcyBhbmQgdGhlIHByZWRpY3RvcnMgdXNpbmcgYSBsaW5lYXIgcmVncmVzc2lvbiB3aXRoIEwyIHJlZ3VsYXJpemF0aW9uLiAgVGhpcyBkcml2ZXMgdGhlIGltcG9ydGFuY2Ugb2YgdW5pbXBvcnRhbnQgYW5kIHJlZHVkYW50IGZlYXR1cmVzIHRvd2FyZHMgemVyby4KCgpgYGB7ciBzYXZlL2xvYWQgbGFzc28gYm9vdHN0cmFwIG1vZGVsIHBlcmZvcm1hbmNlLCBpbmNsdWRlPUZBTFNFfQoKYnNfbGFzc29fcGVyZiA9IE5VTEwKICAKIyBnZXQgZGF0YSBmaWxlcwpic19sYXNzb19wZXJmID0gbG9hZF9mcm9tX2Nzdihic19sYXNzb19wZXJmLCByZXN1bHRzX2RpcmVjdG9yeSwgbm9fdGFza3MpCgoKYGBgCgpgYGB7ciBldmFsdWF0ZSBib290c3RyYXAgbW9kZWwgcGVyZm9ybWFuY2UgbGFzc28sIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cm1lYW5fYnNfbGFzc29fcGVyZiA8LSBic19sYXNzb19wZXJmICU+JQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBtZWFuLCBuYS5ybT1UUlVFKSAlPiUgCiAgbXV0YXRlKG1vZGVsPSdic19sYXNzbycpICU+JQogIGRwbHlyOjpzZWxlY3QobW9kZWwsIGV2ZXJ5dGhpbmcoKSkKCm1lYW5fYnNfbGFzc29fcGVyZgpgYGAKCiMjIyBGZWF0dXJlIGltcG9ydGFuY2VzOiBMQVNTTwojIyMjIENvZWZmaWNpZW50LWJhc2VkIHZhcmlhYmxlIGltcG9ydGFuY2UKCmBgYHtyIHNhdmUvbG9hZCBsYXNzbyBib290c3RyYXAgbW9kZWwgbWRpLCBpbmNsdWRlPUZBTFNFfQoKYnNfbGFzc29fbWRpID0gTlVMTAogIAojIGdldCBkYXRhIGZpbGVzCmJzX2xhc3NvX21kaSA9IGxvYWRfZnJvbV9jc3YoYnNfbGFzc29fbWRpLCByZXN1bHRzX2RpcmVjdG9yeSwgbm9fdGFza3MpCgpgYGAKCmBgYHtyIHNob3cgYnMgbGFzc28gbm9ybWFsaXplZCBjb2VmZmljaWVudHN9CmJvb3RfbGFzc29fbWRpIDwtIGxpc3QoYnNfbGFzc29fbWRpKSAlPiUKICBnZXRfbWVkaWFuX3BsYWNlbWVudCh1c2VfYmFzZV92YXIgPSBUUlVFKSAlPiUKICBhZGRfYXR0cmlidXRlX25hbWVzKCdwcmVkaWN0b3InLCBmdWxsX2RhdGFzZXQpICU+JQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yLCBhdHRfbmFtZSwgb3ZlcmFsbF9yYW5rKQoKaGVhZChib290X2xhc3NvX21kaSwgMjApCmBgYAoKYGBge3IgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9wbGFjZW1lbnRfYm94cGxvdChsaXN0KGJzX2xhc3NvX21kaSkpCmBgYAoKIyMjIyBQZXJtdXRhdGlvbiBpbXBvcnRhbmNlCgpgYGB7ciBjb21wdXRlL3NhdmUgb3IgbG9hZCBicyBsYXNzbyBtb2RlbCBwZXJtdXRhdGlvbiwgaW5jbHVkZT1GQUxTRX0KCmJzX2xhc3NvX3Blcm1fcGx0ID0gTlVMTAogIAojIGdldCBkYXRhIGZpbGVzCmJzX2xhc3NvX3Blcm1fcGx0ID0gbG9hZF9mcm9tX2Nzdihic19sYXNzb19wZXJtX3BsdCwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKYGBgCgoKYGBge3IgYWdncmVnYXRlIGxhc3NvIHBlcm11dGF0aW9ucyBhbmQgZ2V0IG1ldHJpY3N9CmJzX2xhc3NvX3Blcm0gPC0gYnNfbGFzc29fcGVybV9wbHQgJT4lCiAgZ2V0X3Blcm11dGVfcGxhY2VtZW50KG1ldHJpY19vaT1tZXQpICU+JSAjc2V0IGluIHJhbmRvbSBmb3Jlc3Qgc2VjdGlvbgogIGFkZF9hdHRyaWJ1dGVfbmFtZXMoJ3ByZWRpY3RvcicsIGZ1bGxfZGF0YXNldCkgJT4lCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3IsIGV2ZXJ5dGhpbmcoKSkKCmhlYWQoYnNfbGFzc29fcGVybSwgMjApCmBgYAoKYGBge3IgcGxvdCBsYXNzbyBwZXJtdXRhdGlvbiwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9wZXJtdXRlX3Zhcl9pbXAoYnNfbGFzc29fcGVybSwgbWV0cmljID0gbWV0KQpgYGAKCiMjIyMgQ29lZmZpY2llbnQgdnMuIFBlcm11dGF0aW9uIGltcG9ydGFuY2UKTm93LCB3ZSBjb21wYXJlIHRoZSBmZWF0dXJlIGltcG9ydGFuY2VzIGdlbmVyYXRlZCBieSB0aGUgdHdvIGRpZmZlcmVudCBhcHByb2FjaGVzLiAgVGhlIHRyYWRpdGlvbmFsIG1ldGhvZCBvZiBldmFsdWF0aW5nIGZlYXR1cmUgaW1wb3J0YW5jZSBmb3IgcmVncmVzc2lvbiBtZXRob2RzIGlzIHRocm91Z2ggYW5hbHlzaXMgb2YgdGhlIGNvZWZmaWNpZW50cy4KYGBge3IgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxNH0KY2JpbmQoYm9vdF9sYXNzb19tZGlbMToyMCxdLCBkcGx5cjo6c2VsZWN0KGJzX2xhc3NvX3Blcm1bMToyMCxdLCAtbWV0KSkKYGBgCgojIyBDb21wYXJpc29uOiBNb2RlbCBUeXBlIE1lYW4gUGVyZm9ybWFuY2UKVGhlIGZvbGxvd2luZyB0YWJsZSBjb21wYXJlcyB0aGUgbWVhbiBwZXJmb3JtYW5jZSBvZiBib290c3RyYXBwZWQgcmFuZG9tIGZvcmVzdHMgdG8gdGhlIG1lYW4gcGVyZm9ybWFuY2Ugb2YgYm9vdHN0cmFwcGVkIExBU1NPIG1ldGhvZHMuCmBgYHtyIGNvbXBhcmUgYnMgbWVhbiBwZXJmb3JtYW5jZX0KYnNfY29tcF9wZXJmcyA8LSBiaW5kX3Jvd3MobWVhbl9ic19yZl9wZXJmLCBtZWFuX2JzX2xhc3NvX3BlcmYpIApic19jb21wX3BlcmZzCmBgYAoKIyMgQ29tcGFyaXNvbjogTW9kZWwgVHlwZSBGZWF0dXJlIEltcG9ydGFuY2UKSGVyZSwgd2UgbG9vayBhdCB0aGUgYWdncmVnYXRlZCByZXN1bHRzIG9mIHRoZSBib290c3RyYXBwZWQgcHJlZGljdG9ycyBhbmQgY29tcGFyZSB0aGUgbW9kZWxzIGdlbmVyYXRlZCB0byBlYWNoIG90aGVyLgpgYGB7ciBjb21wcmUgYnMgZmVhdHVyZSBpbXBvcnRhbmNlfQpqb2luZWRfcmVzdWx0cyA8LSBic19yZl9wZXJtICU+JQogIGRwbHlyOjpzZWxlY3QoLW1ldCkgJT4lCiAgZnVsbF9qb2luKGRwbHlyOjpzZWxlY3QoYnNfbGFzc29fcGVybSwgLW1ldCksIGJ5PWMoInByZWRpY3RvciIsICJhdHRfbmFtZSIpLCBzdWZmaXg9YygnLnJmJywgJy5sYXNzbycpKSAlPiUKICBtdXRhdGUobWVhbl9yYW5rID0gKG92ZXJhbGxfcmFuay5yZitvdmVyYWxsX3JhbmsubGFzc28pLzIpICU+JQogIGFycmFuZ2UobWVhbl9yYW5rKQoKaGVhZChqb2luZWRfcmVzdWx0cywgMjApCmBgYAoKVGhlIGZvbGxvd2luZyB2aXN1YWxpemF0aW9uIHByb3ZpZGVzIHRoZSBpbnR1aXRpb24gYWJvdXQgdGhlIGRpZmZlcmVuY2VzIGluIHRoZSByYW5raW5ncyBiZXR3ZWVuIG1vZGVsIHR5cGVzLiAgVGhleSdyZSBvcmRlcmVkIGJ5IHRoZSBvdmVyYWxsIG1lYW4gaW1wb3J0YW5jZSwgYW5kIGZvciBhIGdpdmVuIHZhcmlhYmxlLCB0aGUgZGlmZmVyZW5jZXMgaW4gcmFuayBhcmUgc2hvd24uCmBgYHtyIGJzIGZlYXR1cmUgaW1wb3J0YW5jZSBwbG90bHksIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gMTR9CiMgQ29tcGFyaXNvbiBvZiB0b3BfbiBmZWF0dXJlcwpqb2luZWRfcmVzdWx0cyAlPiUKICBjb21wYXJlX2ZlYXR1cmVfc2VsZWN0KGludGVyYWN0aXZlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHRvcF9uID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNTAsCiAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9ycyBieSBNb2RlbCIpCmBgYAoKCiMgR2VuZXJhdGlvbiBvZiBmaW5hbCBtb2RlbCB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCiMjIFJGIG1vZGVsCkluIHRoaXMgc3RlcCwgd2UgYnVpbGQgdGhlIGZpbmFsIG1vZGVsIGZvciB0aGUgcmFuZG9tIGZvcmVzdC4gIFdlIHVzZSBzbGlnaHRseSBtb3JlIHZhbHVlcyBpbiBvcmRlciB0byBjb21lIHVwIHdpdGggdGhlIGJlc3QgbW9kZWwsIGtlZXBpbmcgaW4gbWluZCB0aGUgbnVtYmVyIG9mIGNvbWJpbmF0aW9ucyB0aGF0IGFyZSByZXF1aXJlZCB0byBydW4gdG8gZXZhbHVhdGUgdGhlIGdyaWQuCgpgYGB7ciBzYXZlL2xvYWQgZmluYWwgcmYgbW9kZWx9CgpmaW5hbF9yZl9wZXJmID0gTlVMTAogIAojIHJlYWQgZmlsZSBhcnJheQpmaW5hbF9yZl9wZXJmcyA9IGxvYWRfZnJvbV9jc3YoZmluYWxfcmZfcGVyZiwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKIyBnZXQgdGhlIGluZGV4IG9mIHRoZSBiZXN0IHBlcmZvcm1hbmNlIGFuZCBiZXN0IHBlcmZvcm1hbmNlCmZpbmFsX3JmbW9kZWxfaW5kIDwtIHdoaWNoLm1heChkcGx5cjo6c2VsZWN0KGZpbmFsX3JmX3BlcmZzLCBtZXQpICU+JSBwdWxsKG1ldCkpCmZpbmFsX3JmX3BlcmYgPC0gZmluYWxfcmZfcGVyZnMgJT4lIHNsaWNlKGZpbmFsX3JmbW9kZWxfaW5kKQoKIyBsb2FkIHRoZSBtb2RlbCBvZiBpbnRlcmVzdApmaW5hbF9tb2RlbF9yZiA8LSBsb2FkX2Jlc3RfbW9kZWwoJ2ZpbmFsX3JmX21vZGVsJywgcmVzdWx0c19kaXJlY3RvcnksIGZpbmFsX3JmbW9kZWxfaW5kKQoKYGBgCgojIyMgUGVyZm9ybWFuY2UKVGhlIGZpbmFsIHJhbmRvbSBmb3Jlc3QgcGVyZm9ybWFuY2UgbWV0cmljcyBhcmUgc2hvd24gYmVsb3c6CmBgYHtyIHJmIGZpbmFsIG1vZGVsIHBlcmZvcm1hbmNlfQojIHNob3cgbW9kZWwgZmluYWwgcGVyZm9ybWFuY2UKcHJpbnQoZmluYWxfcmZfcGVyZikKYGBgCgojIyMgRmVhdHVyZXM6IHBlcm11dGF0aW9uIGltcG9ydGFuY2UKCmBgYHtyIGNvbXB1dGUvc2F2ZSBvciBsb2FkIGZpbmFsIHJmIG1vZGVsIHBlcm11dGF0aW9ufQoKZmluYWxfcmZfcGVybV9wbHQgPSBOVUxMCiAgCiMgcmVhZCBiZXN0IHBlcm0gcGx0CmZpbmFsX3JmX3Blcm1fcGx0ID0gbG9hZF9mcm9tX2NzdihmaW5hbF9yZl9wZXJtX3BsdCwgcmVzdWx0c19kaXJlY3RvcnksIGJlc3RfaW5kPWZpbmFsX3JmbW9kZWxfaW5kKQoKYGBgCgoKYGBge3IgZ2V0IG1ldHJpY3MgZm9yIGZpbmFsIHJmfQpmaW5hbF9yZl9wZXJtIDwtIGZpbmFsX3JmX3Blcm1fcGx0ICU+JQogIGdldF9wZXJtdXRlX3BsYWNlbWVudChtZXRyaWNfb2k9bWV0KSAlPiUKICBhZGRfYXR0cmlidXRlX25hbWVzKCdwcmVkaWN0b3InLCBmdWxsX2RhdGFzZXQpICU+JQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yLCBldmVyeXRoaW5nKCkpCgpoZWFkKGZpbmFsX3JmX3Blcm0sIDIwKQpgYGAKCmBgYHtyIHBsb3QgcmYgZmluYWwgcGVybXV0YXRpb24sIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gMTJ9CnBsb3RfcGVybXV0ZV92YXJfaW1wKGZpbmFsX3JmX3Blcm0sIG1ldHJpYyA9IG1ldCkKYGBgCiMjIyBDb21wYXJpc29uIHdpdGggYm9vdHN0cmFwIHJlc3VsdHMKVGhpcyBzZWN0aW9uIGludmVzdGlnYXRlcyB0aGUgZGlmZmVyZW5jZXMgaW4gdGhlIGJvb3RzdHJhcCByZXN1bHRzIHZzIHRoZSBmZWF0dXJlcyBnZW5lcmF0ZWQgZnJvbSB0aGUgcmFuZG9tIGZvcmVzdCBmaW5hbCBtb2RlbC4gIFRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3MgdGhlIG92ZXJhbGwgZGlmZmVyZW5jZXMgaW4gcmFuay4KCmBgYHtyIGNvbXBhcmUgcmYgZmluYWwgd2l0aCBib290c3RyYXB9CnJmX2pvaW5lZF9yZXN1bHRzIDwtIGZpbmFsX3JmX3Blcm0gJT4lCiAgZHBseXI6OnNlbGVjdCgtbWV0KSAlPiUKICBmdWxsX2pvaW4oZHBseXI6OnNlbGVjdChic19yZl9wZXJtLCAtbWV0KSwgYnk9YygicHJlZGljdG9yIiwgImF0dF9uYW1lIiksIHN1ZmZpeD1jKCcuZmluYWwnLCAnLmJvb3RzdHJhcCcpKSAlPiUKICBtdXRhdGUobWVhbl9yYW5rID0gKG92ZXJhbGxfcmFuay5maW5hbCArIG92ZXJhbGxfcmFuay5ib290c3RyYXApLzIpICU+JQogIGFycmFuZ2UobWVhbl9yYW5rKQoKaGVhZChyZl9qb2luZWRfcmVzdWx0cywgMjApCmBgYAoKVGhlIGZvbGxvd2luZyBwbG90IHByb3ZpZGVzIHZpc3VhbGl6YXRpb25zIGZvciB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgZmluYWwgbW9kZWwgcmFua2luZ3MgdnMgdGhlIGJvb3RzdHJhcC4KCmBgYHtyIHBsb3QgZmluYWwgcmYgZmVhdHVyZXMgcGxvdGx5LCBmaWcuaGVpZ2h0PTE0LCBmaWcud2lkdGg9MTZ9CiMgQ29tcGFyaXNvbiBvZiB0b3BfbiBmZWF0dXJlcwpyZl9qb2luZWRfcmVzdWx0cyAlPiUKICBjb21wYXJlX2ZlYXR1cmVfc2VsZWN0KHNlbF9jb2xzID0gYygib3ZlcmFsbF9yYW5rLmZpbmFsIiwgIm92ZXJhbGxfcmFuay5ib290c3RyYXAiKSwKICAgIGludGVyYWN0aXZlID0gVFJVRSwKICAgIHRvcF9uID0gMTAwLAogICAgb3BhY2l0eSA9IDAuNTAsCiAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9yczogRmluYWwgdnMuIEJvb3RzdHJhcCIpCmBgYAoKIyMgTEFTU08gbW9kZWwKTm93LCB3ZSBjcmVhdGUgdGhlIGZpbmFsIG1vZGVsIGZvciBMQVNTTy4gIFRoZXJlIGlzIG5vIHN1YnN0YW50aWFsIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGlzIG1ldGhvZCBhbmQgdGhlIGJvb3RzdHJhcCBtZXRob2RzLCBvdGhlciB0aGFuIHRoZSBkYXRhIHVwb24gd2hpY2ggdGhlIG1vZGVsIGlzIGJlaW5nIGJ1aWx0LgoKYGBge3Igc2F2ZS9sb2FkIGZpbmFsIGxhc3NvIG1vZGVsfQoKZmluYWxfbGFzc29fcGVyZiA9IE5VTEwKICAKIyByZWFkIGZpbGUgYXJyYXkKZmluYWxfbGFzc29fcGVyZnMgPSBsb2FkX2Zyb21fY3N2KGZpbmFsX2xhc3NvX3BlcmYsIHJlc3VsdHNfZGlyZWN0b3J5LCBub190YXNrcykKCiMgZ2V0IHRoZSBpbmRleCBvZiB0aGUgYmVzdCBwZXJmb3JtYW5jZSBhbmQgYmVzdCBwZXJmb3JtYW5jZQpmaW5hbF9sYXNzb21vZGVsX2luZCA8LSB3aGljaC5tYXgoZHBseXI6OnNlbGVjdChmaW5hbF9sYXNzb19wZXJmcywgbWV0KSAlPiUgcHVsbChtZXQpKQpmaW5hbF9sYXNzb19wZXJmIDwtIGZpbmFsX2xhc3NvX3BlcmZzICU+JSBzbGljZShmaW5hbF9sYXNzb21vZGVsX2luZCkKCiMgbG9hZCB0aGUgbW9kZWwgb2YgaW50ZXJlc3QKZmluYWxfbW9kZWxfbGFzc28gPC0gbG9hZF9iZXN0X21vZGVsKCdmaW5hbF9sYXNzb19tb2RlbCcsIHJlc3VsdHNfZGlyZWN0b3J5LCBmaW5hbF9sYXNzb21vZGVsX2luZCkKCmBgYAoKVGhlIGZpbmFsIExBU1NPIHBlcmZvcm1hbmNlIG1ldHJpY3MgYXJlIHNob3duIGJlbG93OgpgYGB7ciBsYXNzbyBmaW5hbCBtb2RlbCBwZXJmb3JtYW5jZX0KIyBzaG93IG1vZGVsIGZpbmFsIHBlcmZvcm1hbmNlCnByaW50KGZpbmFsX2xhc3NvX3BlcmYpCmBgYAoKIyMjIEZlYXR1cmVzOiBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlCgpgYGB7ciBjb21wdXRlL3NhdmUgb3IgbG9hZCBmaW5hbCBsYXNzbyBtb2RlbCBwZXJtdXRhdGlvbn0KCmZpbmFsX2xhc3NvX3Blcm1fcGx0ID0gTlVMTAoKI2xvYWQgYmVzdCBpbmRleCBwZXJtdXRhdGlvbiBmcm9tIGZpbGUgIApmaW5hbF9sYXNzb19wZXJtX3BsdCA9IGxvYWRfZnJvbV9jc3YoZmluYWxfbGFzc29fcGVybV9wbHQsIHJlc3VsdHNfZGlyZWN0b3J5LCBiZXN0X2luZD1maW5hbF9sYXNzb21vZGVsX2luZCkKCgpgYGAKCmBgYHtyIGdldCBwZXJtdXRlIGZlYXR1cmVzIGZvciBmaW5hbCBsYXNzb30KZmluYWxfbGFzc29fcGVybSA8LSBmaW5hbF9sYXNzb19wZXJtX3BsdCAlPiUKICBnZXRfcGVybXV0ZV9wbGFjZW1lbnQobWV0cmljX29pPW1ldCkgJT4lCiAgYWRkX2F0dHJpYnV0ZV9uYW1lcygncHJlZGljdG9yJywgZnVsbF9kYXRhc2V0KSAlPiUKICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvciwgZXZlcnl0aGluZygpKQoKaGVhZChmaW5hbF9sYXNzb19wZXJtLCAyMCkKYGBgCgpgYGB7ciBwbG90IGxhc3NvIGZpbmFsIHBlcm11dGF0aW9uLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEyfQpwbG90X3Blcm11dGVfdmFyX2ltcChmaW5hbF9sYXNzb19wZXJtLCBtZXRyaWMgPSBtZXQpCmBgYAojIyMgQ29tcGFyaXNvbiB3aXRoIGJvb3RzdHJhcCByZXN1bHRzClRoaXMgc2VjdGlvbiBpbnZlc3RpZ2F0ZXMgdGhlIGRpZmZlcmVuY2VzIGluIHRoZSBib290c3RyYXAgcmVzdWx0cyB2cyB0aGUgZmVhdHVyZXMgZ2VuZXJhdGVkIGZyb20gdGhlIExBU1NPIGZpbmFsIG1vZGVsLiAgVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyB0aGUgb3ZlcmFsbCBkaWZmZXJlbmNlcyBpbiByYW5rLgoKYGBge3IgY29tcGFyZSBsYXNzbyBmaW5hbCB3aXRoIGJvb3RzdHJhcH0KbGFzc29fam9pbmVkX3Jlc3VsdHMgPC0gZmluYWxfbGFzc29fcGVybSAlPiUKICBkcGx5cjo6c2VsZWN0KC1tZXQpICU+JQogIGZ1bGxfam9pbihkcGx5cjo6c2VsZWN0KGJzX2xhc3NvX3Blcm0sIC1tZXQpLCBieT1jKCJwcmVkaWN0b3IiLCAiYXR0X25hbWUiKSwgc3VmZml4PWMoJy5maW5hbCcsICcuYm9vdHN0cmFwJykpICU+JQogIG11dGF0ZShtZWFuX3JhbmsgPSAob3ZlcmFsbF9yYW5rLmZpbmFsICsgb3ZlcmFsbF9yYW5rLmJvb3RzdHJhcCkvMikgJT4lCiAgYXJyYW5nZShtZWFuX3JhbmspCgpoZWFkKGxhc3NvX2pvaW5lZF9yZXN1bHRzLCAyMCkKYGBgCgpUaGUgZm9sbG93aW5nIHBsb3QgcHJvdmlkZXMgdmlzdWFsaXphdGlvbnMgZm9yIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBmaW5hbCBtb2RlbCByYW5raW5ncyB2cyB0aGUgYm9vdHN0cmFwLgoKYGBge3IgcGxvdCBsYXNzbyBmZWF0dXJlIGNvbXBhcmlzb24sIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gMTR9CiMgQ29tcGFyaXNvbiBvZiB0b3BfbiBmZWF0dXJlcwpsYXNzb19qb2luZWRfcmVzdWx0cyAlPiUKICBjb21wYXJlX2ZlYXR1cmVfc2VsZWN0KHNlbF9jb2xzID0gYygib3ZlcmFsbF9yYW5rLmZpbmFsIiwgIm92ZXJhbGxfcmFuay5ib290c3RyYXAiKSwKICAgIGludGVyYWN0aXZlID0gVFJVRSwKICAgIHRvcF9uID0gMTAwLAogICAgb3BhY2l0eSA9IDAuNTAsCiAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9yczogRmluYWwgdnMuIEJvb3RzdHJhcCIpCmBgYAoKIyMgQ29tcGFyaXNvbjogRmluYWwgbW9kZWwgZmVhdHVyZXMKSGVyZSwgd2UgY29tcGFyZSB0aGUgZmVhdHVyZXMgZ2VuZXJhdGVkIGJ5IHRoZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIGJldHdlZW4gdGhlIHR3byBmaW5hbCBtb2RlbHMuCgpgYGB7ciBjb21wYXJlIGxhc3NvIHZzIHJhbmRvbSBmb3Jlc3QgZmVhdHVyZXMgZmluYWx9CnJmX2xhc3NvX2ZpbmFsX2pvaW5lZF9yZXN1bHRzIDwtIGZpbmFsX3JmX3Blcm0gJT4lCiAgZHBseXI6OnNlbGVjdCgtbWV0KSAlPiUKICBmdWxsX2pvaW4oZHBseXI6OnNlbGVjdChmaW5hbF9sYXNzb19wZXJtLCAtbWV0KSwgYnk9YygicHJlZGljdG9yIiwgImF0dF9uYW1lIiksIHN1ZmZpeD1jKCcucmYnLCAnLmxhc3NvJykpICU+JQogIG11dGF0ZShtZWFuX3JhbmsgPSAob3ZlcmFsbF9yYW5rLnJmK292ZXJhbGxfcmFuay5sYXNzbykvMikgJT4lCiAgYXJyYW5nZShtZWFuX3JhbmspCgpoZWFkKHJmX2xhc3NvX2ZpbmFsX2pvaW5lZF9yZXN1bHRzLCAyMCkKYGBgCgpUaGUgZm9sbG93aW5nIHZpc3VhbGl6YXRpb24gcHJvdmlkZXMgdGhlIGludHVpdGlvbiBhYm91dCB0aGUgZGlmZmVyZW5jZXMgaW4gdGhlIHJhbmtpbmdzIGJldHdlZW4gdGhlIGZpbmFsIG1vZGVsIHR5cGVzLiAgVGhleSdyZSBvcmRlcmVkIGJ5IHRoZSBvdmVyYWxsIG1lYW4gaW1wb3J0YW5jZSwgYW5kIGZvciBhIGdpdmVuIHZhcmlhYmxlLCB0aGUgZGlmZmVyZW5jZXMgaW4gcmFuayBhcmUgc2hvd24uCgpgYGB7ciBwbG90bHkgbGFzc28gdiByYW5kb20gZm9yZXN0IGZlYXR1cmVzfQojIENvbXBhcmlzb24gb2YgdG9wX24gZmVhdHVyZXMKcmZfbGFzc29fZmluYWxfam9pbmVkX3Jlc3VsdHMgJT4lCiAgY29tcGFyZV9mZWF0dXJlX3NlbGVjdChzZWxfY29scyA9IGMoIm92ZXJhbGxfcmFuay5yZiIsICJvdmVyYWxsX3JhbmsubGFzc28iKSwKICAgIGludGVyYWN0aXZlID0gVFJVRSwKICAgIHRvcF9uID0gMTAwLAogICAgb3BhY2l0eSA9IDAuNTAsCiAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9yczogUmFuZG9tIEZvcmVzdCB2cyBMYXNzbyIpCmBgYAoKIyMgQ29tcGFyaXNvbjogRmluYWwgbW9kZWwgcGVyZm9ybWFuY2UKV2l0aCB0aGUgZmluYWwgbW9kZWxzIGdlbmVyYXRlZCwgd2UncmUgbm93IGFibGUgdG8gY29tcGFyZSB0aGVpciBwZXJmb3JtYW5jZSBtZXRyaWNzLgpgYGB7ciBmaW5hbCBtb2RlbCBjb21wYXJpc29uLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEyfQojIENvbXBhcmlzb24gb2YgcGVyZm9ybWFuY2UgbWV0cmljcwp2YWxpZF9wZXJmIDwtIGdldF9tZXRyaWNfc2V0X2Zyb21fcGVyZnMocGVyZl9saXN0ID0gbGlzdChmaW5hbF9yZl9wZXJmLCBmaW5hbF9sYXNzb19wZXJmKSkgJT4lCiAgbXV0YXRlKG1vZGVsID0gYygncmYnLCAnbGFzc28nKSkKCnRlc3RpbmdfcGVyZiA8LSBnZXRfbWV0cmljX3NldF9mcm9tX21vZGVscyh0ZXN0aW5nX2RmLCBsaXN0KGZpbmFsX21vZGVsX3JmLCBmaW5hbF9tb2RlbF9sYXNzbyksIG91dD1vdXRjb21lKSAlPiUKICBtdXRhdGUobW9kZWwgPSBjKCdyZicsICdsYXNzbycpKQpgYGAKCioqVmFsaWRhdGlvbiBhbmQgc2VsZWN0aW9uLioqClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3MgdGhlIGNvbXBhcmlzb24gYmV0d2VlbiBtb2RlbHMgaW4gdGVybXMgb2YgdGhlIHZhbGlkYXRpb24gc2V0LiAgV2UgY2FuIHNlbGVjdCBvdXIgZmluYWwgbW9kZWwgYmFzZWQgb24gdGhlIGJlc3QgcGVyZm9ybWluZyBtb2RlbCBhY2NvcmRpbmcgdG8gdGhlIG1ldHJpYy4KYGBge3J9CnByaW50KHZhbGlkX3BlcmYpCmBgYAoKKipUZXN0aW5nIHBlcmZvcm1hbmNlLioqClRoZSBmb2xsb3dpbmcgc2hvd3MgdGhlIHBlcmZvcm1hbmNlIG9mIGJvdGggdGhlIG1vZGVscyBvbiB0aGUgdGVzdCBzZXQuICBOb3RlIHRoYXQgYWx0aG91Z2ggd2UgZG9uJ3QgdXNlIHRoaXMgdGVzdCBzZXQgdG8gZXZhbHVhdGUgdGhlIGZpbmFsIG1vZGVscywgd2UgY2FuIHN0aWxsIHNlZSBob3cgb3VyIHNlbGVjdGVkIG1ldGhvZCB3b3VsZCBoYXZlIHBlcmZvcm1lZC4KYGBge3J9CnByaW50KHRlc3RpbmdfcGVyZikKYGBgCgpUaGUgZm9sbG93aW5nIHBsb3RzIHNob3cgYSBjb21wYXJpc29uIGJldHdlZW4gdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbHMgb24gdGhlIHZhbGlkYXRpb24gYW5kIHRlc3Qgc2V0cy4gIEFnYWluLCB3ZSBkb24ndCBjaG9vc2UgdGhlIG1vZGVsIGJhc2VkIG9uIHRoZSB0ZXN0IHNldCwgYnV0IGN1cmlvc2l0eSBkaWN0YXRlcyB0aGF0IHdlIHZpZXcgdGhpcyBwZXJmb3JtYW5jZS4KCmBgYHtyIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNn0KIyBTaG93IHBsb3RzIHNpZGUgYnkgc2lkZQptZXRyaWNzX29mX2ludGVyZXN0ID0gYygnbW9kZWwnLCAnYWNjdXJhY3knLCAnYmFsX2FjY3VyYWN5JywgJ21wY2UnLCAnc2VucycsICdzcGVjJywgJ3BwdicsICducHYnLCAncHJfYXVjJywgJ3JvY19hdWMnKQp2YWxpZF9wbHQgPC0gcGxvdF9tZXRyaWNfc2V0KGRwbHlyOjpzZWxlY3QodmFsaWRfcGVyZiwgYWxsX29mKG1ldHJpY3Nfb2ZfaW50ZXJlc3QpKSwgcGxvdF90aXRsZSA9ICJNb2RlbCBjb21wYXJpc29uIGZvciB2YWxpZGF0aW9uIHNldCIpCnRlc3RfcGx0IDwtIHBsb3RfbWV0cmljX3NldChkcGx5cjo6c2VsZWN0KHRlc3RpbmdfcGVyZiwgYWxsX29mKG1ldHJpY3Nfb2ZfaW50ZXJlc3QpKSwgcGxvdF90aXRsZSA9ICJNb2RlbCBjb21wYXJpc29uIGZvciB0ZXN0aW5nIHNldCIpCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IodmFsaWRfcGx0LCB0ZXN0X3BsdCwgbmNvbD0yLCBucm93PTEpKQpgYGAKIyBPdGhlciBjbGVhbnVwCmBgYHtyIHNodXRkb3duIGgybyBpbnN0YW5jZX0KaDJvLnNodXRkb3duKEZBTFNFKQpgYGA=